/**
 * Candidate number: 35834
 */
package tv.starfu.sequencer.matrix;

import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.NiftyEventSubscriber;
import de.lessvoid.nifty.controls.Controller;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.events.NiftyMousePrimaryClickedEvent;
import de.lessvoid.nifty.elements.render.ImageRenderer;
import de.lessvoid.nifty.input.NiftyInputEvent;
import de.lessvoid.nifty.render.NiftyImage;
import de.lessvoid.nifty.render.NiftyRenderEngine;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.xml.xpp3.Attributes;
import java.util.ArrayList;
import java.util.Properties;
import org.bushe.swing.event.EventTopicSubscriber;
import tv.starfu.sequencer.model.SequencerModel;

/**
 * Controller class for Matrix Atoms
 * @author niadzi
 */

public class MatrixAtomController implements Controller {

    private Nifty nifty;
    private Screen screen; 
    private Element element;
    
    // List of images (button, hover, active, cued)
    private ArrayList<NiftyImage> images;
    private Element image;
   // private MatrixAtom atom;
    
    // Matrix Atom state data
    private int phase;
    private int channel;
    private int step;
    private String phaseString;
    private String channelID;
    private String stepID;
    
    // Stores patterns
    private static SequencerModel seqModel;
    
    public MatrixAtomController() {
        MatrixAtomController.seqModel = seqModel;
    }
    
    /**
     * binds Controller to GUI Control
     * @param nifty     Nifty instance
     * @param screen    Screen instance
     * @param element   The element to watch/contol
     * @param parameter Control parameters
     * @param controlDefinitionAttributes 
     */
    public void bind(Nifty nifty, 
                     Screen screen, 
                     Element element, 
                     Properties parameter, 
                     Attributes controlDefinitionAttributes) {
        
        this.nifty = nifty;
        this.screen = screen;
        this.element = element;
        this.image = element;
        
        // Get initial state data
        this.phaseString = (parameter.getProperty("phase"));
        this.channelID = (parameter.getProperty("channel"));
        this.stepID = (parameter.getProperty("step"));
        
        // Convert state data to integers
        phase = Integer.parseInt(phaseString);
        channel = Integer.parseInt(channelID);
        step    = Integer.parseInt(stepID);
        
//        atom.setPhase(phase);
//        atom.setChannel(channel);
//        atom.setStep(step);
        
        // Create button icons
        images = new ArrayList<NiftyImage>();
        images = createImages(nifty.getRenderEngine());

        // Display the element
        updateButton(element.getId());
    }

    @Override
    public void init(Properties parameter, Attributes controlDefinitionAttributes) {    
        
        // Listen to mouse clicks : maybe move to a different method
        /* Create Listener ('subscriber') for MouseClicks */
        EventTopicSubscriber<NiftyMousePrimaryClickedEvent> mouseClickedSubscriber = 
                new EventTopicSubscriber<NiftyMousePrimaryClickedEvent>() {
              /* Define listener ('subscriber') action : create a new Matrix Event */
              @Override
              public void onEvent(final String topic, final NiftyMousePrimaryClickedEvent data) {
                /* Publish Matrix Event with element ID, phase, channel and step state data */
                nifty.publishEvent(topic, new MatrixAtomPhaseChangedEvent(element.getId(), phase, channel, step));
                /* Update visual element */
                updateButton(element.getId());
              }
        };
        /* Set nifty screen and element to listen for MouseClicked Event */
        nifty.subscribe(screen, element.getId(), NiftyMousePrimaryClickedEvent.class, mouseClickedSubscriber);
    }

    /**
     * Element action on starting screen. Currently fades in.
     */
    public void onStartScreen() {
       //DEBUG: System.out.println("onStartScreen() called for element: " + element.getId());
    }

    /**
     * Element action on user-input focus.
     * @param getFocus  user focus
     */
    @Override
    public void onFocus(boolean getFocus) {
        
    }

    public boolean inputEvent(NiftyInputEvent inputEvent) {
        return true;
    }
   
    /**
     * create and store button images
     * @param renderDevice  renderDevice
     * @return NiftyImage   ArrayList of images.
     */
    private ArrayList<NiftyImage> createImages(final NiftyRenderEngine renderDevice) {
            //String property = nifty.specialValuesReplace(param);
        /* Add button images to list */
        images.add(renderDevice.createImage("Interface/circles/Circle/32x32/button_circle_aqua_normal_32x32.png", false));
        images.add(renderDevice.createImage("Interface/circles/Circle/32x32/button_circle_purple_normal_32x32.png", false));
        images.add(renderDevice.createImage("Interface/circles/Circle/32x32/button_circle_aqua_mouse_over_32x32.png", false));  
        return images;
    }

    /**
     * If phase of Matrix Atom is changed, publish new Matrix Event.
     */
    private void phaseChanged() {
      nifty.publishEvent(element.getId(), new MatrixAtomPhaseChangedEvent(element.getId(), phase, channel, step));
      /* Update visual element */
      updateButton(element.getId());
    }    
    
  /**
     * Listen for Matrix Phase Change Events on elements with names beginning 'mb'.
     * @param id    Element Id
     * @param event incoming MatrixAtomPhaseChangedEvent
     */
    @NiftyEventSubscriber(pattern="mb.*")
    public void onClick(final String id, final MatrixAtomPhaseChangedEvent event) {
      
      /* If this element is clicked and its phase is zero... */
      if(id.equals(image.getId()) && event.getPhase() == 0) {
          /* Set Matrix Atom phase to 1 */
          phase = 1;
          /* Update GUI */
          updateButton(id);
      }
      
      else if(id.equals(image.getId()) && event.getPhase() == 1) {
          phase = 0;
          updateButton(id);
      }
  }
    
    /**
     * Update button image according to current phase
     * @param id    Element id
     */
    private void updateButton(String id) {
        NiftyImage currentImage = images.get(phase);
        if(image.getId().equals(id)) {
            image.getRenderer(ImageRenderer.class).setImage(currentImage);
            image.setWidth(32);
            image.setHeight(32);
            image.layoutElements();
        }
    }

    public void nextPhase() {
        phase++;
        phaseChanged();
    }


    public int getPhase() {
        return phase;
    }

    public void setPhase(int phaseIndex) {
        phase = phaseIndex;
        phaseChanged();
        
    }

    public String getId() {
        return image.getId();
    }

    public void setId(String id) {
        image.setId(id);
    }

    public void setChannelID(String channelID) {
        this.channelID = channelID;
    }
    
    public void setStepID(String stepID) {
        this.stepID = stepID;
    }

    public String getChannelID() {
        return channelID;
    }

    public String getStepID() {
        return stepID;
    }

}
